package im.redis.client.operations;

import im.redis.client.JedisTemplate;
import im.redis.client.JedisTemplate.JedisAction;

import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;

import com.google.common.collect.Lists;

public class SortedSetOperation {
	private JedisTemplate template;

	public SortedSetOperation(JedisTemplate template) {
		super();
		this.template = template;
	}

	// / Ordered Set Actions ///
	/**
	 * return true for add new element, false for only update the score.
	 */
	public Boolean zadd(final String key, final double score, final String member) {
		return template.execute(new JedisAction<Boolean>() {

			@Override
			public Boolean action(Jedis jedis) {
				return jedis.zadd(key, score, member) == 1 ? true : false;
			}
		});
	}

	public Double zscore(final String key, final String member) {
		return template.execute(new JedisAction<Double>() {

			@Override
			public Double action(Jedis jedis) {
				return jedis.zscore(key, member);
			}
		});
	}

	public Long zrank(final String key, final String member) {
		return template.execute(new JedisAction<Long>() {

			@Override
			public Long action(Jedis jedis) {
				return jedis.zrank(key, member);
			}
		});
	}

	public Long zrevrank(final String key, final String member) {
		return template.execute(new JedisAction<Long>() {

			@Override
			public Long action(Jedis jedis) {
				return jedis.zrevrank(key, member);
			}
		});
	}

	public Long zcount(final String key, final double min, final double max) {
		return template.execute(new JedisAction<Long>() {

			@Override
			public Long action(Jedis jedis) {
				return jedis.zcount(key, min, max);
			}
		});
	}

	public Set<String> zrange(final String key, final int start, final int end) {
		return template.execute(new JedisAction<Set<String>>() {

			@Override
			public Set<String> action(Jedis jedis) {
				return jedis.zrange(key, start, end);
			}
		});
	}

	public Set<Tuple> zrangeWithScores(final String key, final int start, final int end) {
		return template.execute(new JedisAction<Set<Tuple>>() {

			@Override
			public Set<Tuple> action(Jedis jedis) {
				return jedis.zrangeWithScores(key, start, end);
			}
		});
	}

	public Set<String> zrevrange(final String key, final int start, final int end) {
		return template.execute(new JedisAction<Set<String>>() {

			@Override
			public Set<String> action(Jedis jedis) {
				return jedis.zrevrange(key, start, end);
			}
		});
	}

	public Set<Tuple> zrevrangeWithScores(final String key, final int start, final int end) {
		return template.execute(new JedisAction<Set<Tuple>>() {

			@Override
			public Set<Tuple> action(Jedis jedis) {
				return jedis.zrevrangeWithScores(key, start, end);
			}
		});
	}

	public Set<String> zrangeByScore(final String key, final double min, final double max) {
		return template.execute(new JedisAction<Set<String>>() {

			@Override
			public Set<String> action(Jedis jedis) {
				return jedis.zrangeByScore(key, min, max);
			}
		});
	}

	public Set<Tuple> zrangeByScoreWithScores(final String key, final double min, final double max) {
		return template.execute(new JedisAction<Set<Tuple>>() {

			@Override
			public Set<Tuple> action(Jedis jedis) {
				return jedis.zrangeByScoreWithScores(key, min, max);
			}
		});
	}

	public Set<String> zrevrangeByScore(final String key, final double max, final double min) {
		return template.execute(new JedisAction<Set<String>>() {

			@Override
			public Set<String> action(Jedis jedis) {
				return jedis.zrevrangeByScore(key, max, min);
			}
		});
	}

	public Set<Tuple> zrevrangeByScoreWithScores(final String key, final double max, final double min) {
		return template.execute(new JedisAction<Set<Tuple>>() {

			@Override
			public Set<Tuple> action(Jedis jedis) {
				return jedis.zrevrangeByScoreWithScores(key, max, min);
			}
		});
	}

	public Boolean zrem(final String key, final String member) {
		return template.execute(new JedisAction<Boolean>() {

			@Override
			public Boolean action(Jedis jedis) {
				return jedis.zrem(key, member) == 1 ? true : false;
			}
		});
	}

	public Long zremByScore(final String key, final double start, final double end) {
		return template.execute(new JedisAction<Long>() {

			@Override
			public Long action(Jedis jedis) {
				return jedis.zremrangeByScore(key, start, end);
			}
		});
	}

	public Long zremByRank(final String key, final long start, final long end) {
		return template.execute(new JedisAction<Long>() {

			@Override
			public Long action(Jedis jedis) {
				return jedis.zremrangeByRank(key, start, end);
			}
		});
	}

	public Long zcard(final String key) {
		return template.execute(new JedisAction<Long>() {

			@Override
			public Long action(Jedis jedis) {
				return jedis.zcard(key);
			}
		});
	}

	/** 查看第一个元素 */
	public String peekFirst(String key) {
		Set<String> set = zrange(key, 0, 0);
		if (set == null || set.isEmpty()) {
			return null;
		}
		return set.iterator().next();
	}

	/** 查看最后一个元素 */
	public String peekLast(String key) {
		Set<String> set = zrevrange(key, 0, 0);
		if (set == null || set.isEmpty()) {
			return null;
		}
		return set.iterator().next();
	}

	private static final String SCRIPT = "local arr = redis.call(KEYS[1],KEYS[2],ARGV[1],ARGV[2]) if arr == nil then return nil end redis.call('zrem',KEYS[2],arr[1]) return arr[1]";

	/** 移除并返回第一个元素 */
	public String first(String key) {
		return template.eval(SCRIPT, Lists.newArrayList("zrange", key), Lists.newArrayList("0", "0"));
	}

	/** 移除并返回最后一个元素 */
	public String last(String key) {
		return template.eval(SCRIPT, Lists.newArrayList("zrevrange", key), Lists.newArrayList("0", "0"));
	}

	private static final String SCRIPT_EXPECTED = "local arr = redis.call(KEYS[1],KEYS[2],ARGV[1],ARGV[2]) if arr == nil then return nil end local target = arr[1] if target == ARGV[3] then redis.call('zrem',KEYS[2],arr[1]) return arr[1] end return nil";

	/** 如果第一个元素是所期望的，则移除并返回 */
	public String expectFirst(String key, String expected) {
		return template.eval(SCRIPT_EXPECTED, Lists.newArrayList("zrange", key), Lists.newArrayList("0", "0", expected));
	}

	/** 如果最后一个元素是所期望的，则移除并返回 */
	public String expectLast(String key, String expected) {
		return template.eval(SCRIPT_EXPECTED, Lists.newArrayList("zrevrange", key), Lists.newArrayList("0", "0", expected));
	}
}
